package com.spzx.auth.service;

import com.spzx.auth.form.RegisterBody;
import com.spzx.common.core.constant.CacheConstants;
import com.spzx.common.core.constant.Constants;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.constant.UserConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.enums.UserStatus;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.text.Convert;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.core.utils.ip.IpUtils;
import com.spzx.common.redis.service.RedisService;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.system.api.model.LoginUser;
import com.spzx.user.api.RemoteUserInfoService;
import com.spzx.user.api.domain.UpdateUserLogin;
import com.spzx.user.api.domain.UserInfo;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Haoran Sun
 * @since 2024/07/29
 */

@Component
public class H5LoginService {

    @Resource
    private RemoteUserInfoService remoteUserInfoService;
    @Resource
    private SysRecordLogService rsLogService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private SysPasswordService passwordService;
    @Resource
    private RedisService redisService;

    private static final String CHINA_MOBILE_PHONE_PATTERN = "^1[3-9]\\d{9}$";

    /**
     * 注册
     *
     * @param registerBody 注册信息
     */
    public void register(RegisterBody registerBody) {
        String username = registerBody.getUsername();
        String password = registerBody.getPassword();
        String code = registerBody.getCode();
        String nickName = registerBody.getNickName();
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, password)) {
            throw new ServiceException("用户/密码必须填写");
        }
        if (username.length() != 11) {
            throw new ServiceException("账户长度必须是11个字符");
        }
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            throw new ServiceException("密码长度必须在5到20个字符之间");
        }
        if (StringUtils.isEmpty(code)) {
            throw new ServiceException("验证码必须填写");
        }

        String codeValue = stringRedisTemplate.opsForValue().get("phone:code:" + username);
        if (!code.equals(codeValue)) {
            throw new ServiceException("验证码错误");
        }
        // 注册用户
        UserInfo userInfo = UserInfo.builder()
                .username(username)
                .password(SecurityUtils.encryptPassword(password))
                .nickName(StringUtils.isEmpty(nickName) ? username : nickName)
                .build();

        R<Boolean> registerResult = remoteUserInfoService.register(userInfo, SecurityConstants.INNER);

        if (!R.isSuccess(registerResult)) {
            throw new ServiceException(registerResult.getMsg());
        }
        rsLogService.recordLogininfor(username, Constants.REGISTER, "注册成功");
    }

    /**
     * 登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录用户
     */
    public LoginUser login(String username, String password) {
        if (StringUtils.isAnyBlank(username, password)) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
            throw new ServiceException("用户/密码必须填写");
        }
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "密码长度必须在5到20个字符之间");
            throw new ServiceException("密码长度必须在5到20个字符之间");
        }
        if (username.length() != 11) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "账户长度必须是11个字符");
            throw new ServiceException("账户长度必须是11个字符");
        }
        Pattern pattern = Pattern.compile(CHINA_MOBILE_PHONE_PATTERN);
        Matcher matcher = pattern.matcher(username);
        if (!matcher.matches()) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "手机号格式错误");
            throw new ServiceException("手机号格式错误");
        }

        String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST));
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录失败，该IP已被列入系统黑名单");
            throw new ServiceException("登录失败，该IP已被列入系统黑名单");
        }
        R<UserInfo> userResult = remoteUserInfoService.getUserInfo(username, SecurityConstants.INNER);
        if (!R.isSuccess(userResult)) {
            throw new ServiceException(userResult.getMsg());
        }
        if (userResult.getData() == null) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录失败，用户不存在");
            throw new ServiceException("登录失败，用户不存在");
        }
        UserInfo userInfo = userResult.getData();
        if (userInfo.getStatus()==0) {
            rsLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录失败，用户被停用");
            throw new ServiceException("登录失败，用户被停用");
        }
        LoginUser loginUser = LoginUser.builder()
                .userid(userInfo.getId())
                .username(userInfo.getUsername())
                .password(userInfo.getPassword())
                .status(userInfo.getStatus().toString()).build();
        passwordService.validate(loginUser, password);
        rsLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
        remoteUserInfoService.updateUserLogin(UpdateUserLogin.builder()
                .userId(userInfo.getId())
                .lastLoginIp(IpUtils.getIpAddr())
                .lastLoginTime(LocalDate.now())
                .build(), SecurityConstants.INNER);

        return loginUser;
    }
}
